package cn.tedu.csmall.stock.webapi.controller;

import cn.tedu.csmall.commons.exception.CoolSharkServiceException;
import cn.tedu.csmall.commons.pojo.stock.dto.StockReduceCountDTO;
import cn.tedu.csmall.commons.restful.JsonResult;
import cn.tedu.csmall.commons.restful.ResponseCode;
import cn.tedu.csmall.stock.service.IStockService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.json.Json;

@RestController
@RequestMapping("/base/stock")
@Api(tags = "库存管理模块")
public class StockController {
    @Autowired
    private IStockService stockService;

    @GetMapping("/reduce/count")
    @ApiOperation("减少指定商品的库存数")
    // @SentinelResource注解需要标记在控制层方法上,在该方法运行一次后,
    // 会被Sentinel仪表台检测到,并显示在仪表台中
    // 如果这个方法不运行,仪表台中不会显示这个方法
    // 括号中"减少库存数",会作为方法的名称出现在仪表台上,代表这个方法
    // blockHandler可以设置当前控制器方法被限流时,要运行的自定义限流方法,blockError是方法名称
    @SentinelResource(value = "减少库存数",
            blockHandler = "blockError",
            fallback = "fallbackError")
    public JsonResult reduceCommodityCount(
            StockReduceCountDTO stockReduceCountDTO){
        // 调用业务逻辑层方法
        stockService.reduceCommodityCount(stockReduceCountDTO);
        // 为了测试并发线程数,让每次方法运行的时间长一些,这里要阻塞线程方便测试
    //        try {
    //            Thread.sleep(5000);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
//        if(Math.random()<0.5){
//            throw new CoolSharkServiceException(
//                    ResponseCode.INTERNAL_SERVER_ERROR,"发生随机异常!");
//        }
        return JsonResult.ok("库存减少完成!");
    }

    // Sentinel自定义限流方法定义规则
    // 1.访问修饰符必须是public
    // 2.返回值类型必须和被限流的控制器方法一致
    // 3.方法名必须和控制器限流注解中blockHandler属性定义的方法名称一致
    // 4.方法参数,先编写和控制器方法一致的参数信息,再额外添加BlockException类型的参数
    public JsonResult blockError(StockReduceCountDTO stockReduceCountDTO,
                                 BlockException e){
        // 这个方法运行,表示当前控制器访问数已经超过设计的最大值
        // 我们需要给前端反馈,服务器忙,本次请求被限流
        return JsonResult.failed(
                ResponseCode.INTERNAL_SERVER_ERROR,"服务器忙,请稍后再试");

    }
    // 自定义降级方法: 由@SentinelResource注解的fallback属性指定的方法
    // 自定义降级方法和自定义限流方法的格式基本是一致的
    // 区别是降级方法参数额外的异常类型要使用Throwable
    // 这个方法会在原有控制器方法运行发生异常是触发
    // 实际开发中,可能调用一些老版本代码,所以称之为降级
    public JsonResult fallbackError(StockReduceCountDTO stockReduceCountDTO,
                                    Throwable throwable){
        // 先将异常信息输出到日志(控制台)
        throwable.printStackTrace();
        // 返回降级方法运行的信息
        return JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR,
                                "因为发生异常,服务降级");
    }


}
